import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import static java.lang.constant.ConstantDescs.CD_int;
import static java.lang.constant.ConstantDescs.CD_void;

@SuppressWarnings({"ExplicitToImplicitClassMigration", "RedundantSuppression", "CodeBlock2Expr"})
public class TestClassAPI extends ClassLoader {
	public static void main(String[] args) throws Exception {
		var cf = ClassFile.of();
		var bytes = cf.build(ClassDesc.of("Test"), classBuilder -> {
			classBuilder.withMethod("method", MethodTypeDesc.of(CD_void, CD_int.arrayType(), CD_int, CD_int),
					ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC, mb -> {
						mb.withCode(cb -> cb // void swap(int[] a, int i, int j)
								.aload(cb.parameterSlot(0)) // a
								.iload(cb.parameterSlot(1)) // a,i
								.aload(cb.parameterSlot(0)) // a,i,a
								.iload(cb.parameterSlot(2)) // a,i,a,j
								.iaload()                   // a,i,a[j]
								.aload(cb.parameterSlot(0)) // a,i,a[j],a
								.iload(cb.parameterSlot(2)) // a,i,a[j],a,j
								.aload(cb.parameterSlot(0)) // a,i,a[j],a,j,a
								.iload(cb.parameterSlot(1)) // a,i,a[j],a,j,a,i
								.iaload()                   // a,i,a[j],a,j,a[i]
								.iastore()                  // a,i,a[j]   a[j]=a[i]
								.iastore()                  // a[i]=a[j]  a[j]=a[i]
								.return_());
					});
		});

		var cls = new TestClassAPI().defineClass("Test", bytes, 0, bytes.length);
		var method = cls.getMethod("method", int[].class, int.class, int.class);
		var a = new int[]{1, 2};
		method.invoke(null, a, 0, 1);
		System.out.println(a[0]);
		System.out.println(a[1]);
	}
}
